#include "client.h"
#include "ui_client.h"
#include "global.h"
#include <QGridLayout>
#include <QHostInfo>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QMessageBox>
#include <QListWidgetItem>
#include <QDebug>
#include <QTimer>

Client::Client(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Client)
{
    ui->setupUi(this);

    initUI();

    initAll();

}

Client::~Client()
{
    delete ui;
}

void Client::initUI()
{
    // 使 listWidget 撑满整个 groupBox
    QGridLayout *layout = new QGridLayout();
    layout->addWidget(ui->listWidget);
    ui->groupBox->setLayout(layout);

    // 设置顶层窗口标题
    this->setWindowTitle("chat");
}

void Client::initAll(){   

    tcpSocket = new QTcpSocket(this);
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onTcpReadyRead()));

    udpSocket = new QUdpSocket(this);
    udpSocket->bind(port);
    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));

    connect(ui->listWidget,SIGNAL(itemDoubleClicked(QListWidgetItem*)),this,SLOT(onItemDoubleClicked(QListWidgetItem*)));
}


void Client::onReadyRead()
{
    while(udpSocket->hasPendingDatagrams()){
        QHostAddress peerIP;
        QByteArray data;
        data.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(data.data(),data.size(),&peerIP);
        if(peerIP.toString().contains(ip)) return;

        QString targetUsername;   // 目标用户名
        int msgType;    // 此处是 int 类型，不是 udpMsgType 类型。枚举类型的值其实就是int类型的

        QDataStream stream(&data,QIODevice::ReadOnly);

        // 以 “用户名 -> 消息类型” 的反序列化形式读取出数据
        stream >> targetUsername >> msgType;

        switch(msgType){

        case Msg:{
            QString content;
            stream >> content;
            ui->textBrowser->append(targetUsername + " : " + content);
            break;
        }


        case UserEnter:{
            QString targetIp;
            stream >> targetIp;
            updateOnlineList(login,targetUsername,targetIp);  // 更新用户名
            break;
        }

        case UserLeft:
            break;

        case FileName:
            break;


        case Refuse:
            break;



        }


    }
}

void Client::onTcpReadyRead()
{
    QString item;
    while(tcpSocket->canReadLine())    {
        item = tcpSocket->readLine();
        ui->listWidget->addItem(item);
    }
    ui->groupBox->setTitle(tr("在线成员"));
}

void Client::onItemDoubleClicked(QListWidgetItem *item)
{
    if(item->text() == "全体成员"){
        targetUsername = "全体成员";
    }else{
        QList<QString> aList = item->text().split(" : ");
        targetUsername = aList.at(0);
        targetIp = aList.at(1);
    }
    ui->label->setText(tr("聊天对象 : ") + targetUsername);
}

bool Client::getValidIP()
{
    QTcpSocket *getValidIPSocket = new QTcpSocket(this);
    getValidIPSocket->connectToHost(serverIP,port);  // 通过阻塞的方式访问 Google 的服务器，然后通过这种方法获取有效IP地址
    if(getValidIPSocket->waitForConnected()){
        ip = getValidIPSocket->localAddress().toString();
        ui->statusbar->setStatusTip(tr("*本机IP：") + ip + tr("*"));
        return true;
    }else{
        return false;
    }
}

void Client::setUserName(const QString &username)
{
    this->username = username;
}

void Client::broadcastInfo()
{
    sendMsg(broadcast,UserEnter);   // 以广播形式发送数据，并指定数据类型为 “新用户加入”
}

bool Client::connectServer()
{     
     tcpSocket->connectToHost(serverIP,port);
     if(tcpSocket->waitForConnected() == false) return false;

     // 发送心跳包给服务端
     QTimer *timer = new QTimer(this);
     connect(timer,&QTimer::timeout,this,[&](){
         QString msgType = "KeepAlivePacket";
         QString item;
         item = username + " : " + ip;
         sendTcpMsg(msgType,item);
     });
     timer->start(5000);

     return true;
}

void Client::disconnectServer()
{
    tcpSocket->disconnectFromHost();
    if(tcpSocket->waitForDisconnected()){

    }
}

void Client::sendLocalInfoToServer()
{
    QString item;
    item = username + " : " + ip;
    sendTcpMsg("UserEnter",item);
}

void Client::logOut(QString out)
{
    QDialog *dialog = new QDialog();
    QLabel *label = new QLabel("日志输出 = " + out,dialog);
    dialog->exec();
}

void Client::sendMsg(const udpCommunicationMode &mode, const udpMsgType &msgType, const QString &targetIP, const QString &content)
{
    QByteArray data;
    QDataStream stream(&data,QIODevice::WriteOnly);

    stream << username << msgType;  // 以 “用户名 -> 消息类型” 的序列化形式写入到数据流中

    switch (msgType) {

    case Msg:
        stream << content;
        break;

    case UserEnter:
        stream << ip;
        break;

    case UserLeft:
        stream << ip;
        break;

    case FileName:
        break;


    case Refuse:
        break;

    }

    switch(mode){

    case unicast:
        udpSocket->writeDatagram(data,data.size(),QHostAddress(targetIP),port);
        break;

    case broadcast:
        udpSocket->writeDatagram(data,data.size(),QHostAddress::Broadcast,port);
        break;


    }

}

void Client::updateOnlineList(const userType &type, const QString &username, const QString &ip)
{
    if(ip == this->ip) return;

    switch (type) {

    case login:{
        QString item = username + " : " +ip;
        ui->listWidget->addItem(item);
        break;
    }

    case logout:
        break;

    }
}

void Client::sendTcpMsg(const QString &msgType, const QString item)
{
    // KeepAlivePacket ： 心跳包
    qDebug() << msgType;

    QString msg = msgType + ";" + item;
    QByteArray data = msg.toUtf8();
    data.append('\n');// 必须要加，否则 canReadLine() 返回的是false
    tcpSocket->write(data,data.length());
}

void Client::on_btnSend_clicked()
{
    QString msg = ui->plainTextEdit->toPlainText();
    if(msg.isEmpty())return;
    QString content = username + " : " + msg;

    ui->textBrowser->append(content);

    ui->plainTextEdit->clear();
    ui->plainTextEdit->setFocus();

    if(targetUsername == "全体成员")
        sendMsg(broadcast,Msg,"",msg);
    else
        sendMsg(unicast,Msg,targetIp,msg);
}

void Client::closeEvent(QCloseEvent *event)
{
//    if(tcpSocket->state() != QAbstractSocket::UnconnectedState) event->ignore();
    // 如果 依然连接着服务器，则不允许直接关闭
}

void Client::on_btnSend_2_clicked()
{
    QString item = username + " : " + ip;
    sendTcpMsg("UserLeft",item);

    QLabel *label = new QLabel(tr("退出中……"),this);
    ui->statusbar->addPermanentWidget(label);

    QTimer::singleShot(5000, this, [=](){
           disconnectServer();
           this->close();
           loginScreen *w = new loginScreen();
           w->show();
    });

}
